const { app, BrowserWindow, ipcMain, dialog, screen, shell } = require('electron');
///node.js写入数据
const fs = require('fs');
const os = require('os');
const path = require('node:path');
const { exec } = require('child_process');
const { spawn } = require('child_process');
require('./js/util/extensions.js');

const SerialPort = require("serialport");
const SerialPortStore = require('./js/model/serialport_model.js'); // 导入模型类
const { AddressModel, ChannelModel, BaseModel } = require('./js/model/model.js');
const StorageManager = require('./js/util/storage_manager.js')
const { write } = require('node:fs');
let screenSize = null; // 获取主屏幕的工作区域大小
// const { list } = require('serialport');

let colorPickerProcess = null; // 存储颜色选择器进程
let isColorPickerOpen = false; // 标志位，用于跟踪颜色选择器是否已经打开

let mainWindow;
let popupWindow;
let port = null;
// Handle creating/removing shortcuts on Windows when installing/uninstalling.
if (require('electron-squirrel-startup')) {
  app.quit();
}

async function createWindow() {
  if (mainWindow) {
    console.log(`已经创建了窗口`);
    mainWindow.show();
    return; // 如果已经有窗口，就不再创建新的窗口
  }
  initData();
  screenSize = screen.getPrimaryDisplay().workAreaSize;
  // Create the browser window.
  mainWindow = new BrowserWindow({
    x: 500,
    width: screenSize.width - 500,
    height: screenSize.height,
    autoHideMenuBar: true,
    webPreferences: {
      preload: path.join(__dirname, 'preload.js'),
      devTools: true,  // 禁用开发者工具
      contextIsolation: true,  //启用上下文隔离，确保安全性。
      //情况 1️⃣ 如果 nodeIntegration: true（如上面代码）
      // 🔹 可以 直接在 renderer.js 里使用 require('electron')，不需要 preload.js。
      //情况 2️⃣ 如果 nodeIntegration: false（安全模式，推荐）
      // 🔹 需要 preload.js 来暴露 ipcRenderer，否则渲染进程无法直接访问 require('electron')。
      nodeIntegration: true
    },
  });
  mainWindow.setBounds({ x: 500, y: 0, width: screenSize.width - 500, height: screenSize.height });

  handleActions();
  // createLogWindow();
  // and load the index.html of the app.
  // mainWindow.loadFile(path.join(__dirname, '../index.html'));
  mainWindow.loadFile(path.join(__dirname, 'html/index.html'));
  mainWindow.on('close', (event) => {
    if (process.platform === 'darwin') {
      event.preventDefault();
      mainWindow.hide();
      hiddenLogWindow();
    } else {
      mainWindow = null;
      logWindow.close();
      logWindow = null;
    }
    closePopupWindow();
  });

  mainWindow.on('hide', () => {
    hiddenLogWindow();
    // closePopupWindow();
  });
  mainWindow.on('ready-to-show', () => {
    createLogWindow();
  });
};


// This method will be called when Electron has finished
// initialization and is ready to create browser windows.
// Some APIs can only be used after this event occurs.
app.whenReady().then(() => {
  createWindow();
  // On OS X it's common to re-create a window in the app when the
  // dock icon is clicked and there are no other windows open.
  app.on('activate', () => {
    if (BrowserWindow.getAllWindows().length === 0) {
      createWindow();
    } else {
      mainWindow.show();
    }
  });
});

// Quit when all windows are closed, except on macOS. There, it's common
// for applications and their menu bar to stay active until the user quits
// explicitly with Cmd + Q.
app.on('window-all-closed', () => {
  if (process.platform !== 'darwin') {
    app.quit();
  }
});

function handleActions() {
  ipcMain.on('showColorPicker', showColorPicker);
  ipcMain.handle('chooseFile', chooseFile);
  ipcMain.on('close-popup', closePopupWindow);
  ipcMain.on('open-popup', openPopupWindow);
  ipcMain.on('set-window-size', setWindowSize);
  ipcMain.handle('browse-files', browseFiles);
  ipcMain.handle('app_version', getAppVersion);
  ipcMain.handle('read-files', readFiles);
  ipcMain.handle('serial-list', getSerialList)
  ipcMain.on('open-port', openPort);
  ipcMain.on('close-port', closePort);
  ipcMain.on('send-data', sendData);
  ipcMain.on('send-data-model-list', sendDataWithList);
  ipcMain.handle('get-current-port', getCurrenPort);
  ipcMain.handle('load-all-address', loadAllAddress);
  ipcMain.handle('update-address', updateAddress);
  ipcMain.handle('find-address-id', findAddress);
  ipcMain.handle('get-store-value', getStoreValue);
  ipcMain.on('set-store-value', setStoreValue);
  ipcMain.on('open-log-window', createLogWindow);
  ipcMain.handle('load-all-channel', loadAllChannel);
  ipcMain.handle('update-channel', updateChannel);
  ipcMain.on('send-signal-select', receiveSignSelect);
}

function getCurrenPort() {
  return port == null ? null : {
    path: port.path,
    manufacturer: port.manufacturer,
    serialNumber: port.serialNumber,
    pnpId: port.pnpId,
    locationId: port.locationId,
    vendorId: port.vendorId,
    productId: port.productId
  };
}

///获取app版本号
async function getAppVersion() {
  return await app.getVersion();
}
///弹出指定弹窗
function openPopupWindow(_, fileName, width = 400, height = 300, fileData) {
  if (popupWindow) {
    closePopupWindow();
    return;
  }
  popupWindow = new BrowserWindow({
    width: width,
    height: height,
    autoHideMenuBar: true,
    parent: mainWindow, // 设置父窗口
    modal: false, // true为模态窗口，模态窗口不会显示系统取消按钮
    resizable: false,// 禁止调整窗口大小
    maximizable: false, // 禁用最大化按钮
    minimizable: false, // 禁止最小化窗口
    movable: false,//禁止移动窗口。
    webPreferences: {
      preload: path.join(__dirname, 'preload.js'),
      nodeIntegration: true,
      contextIsolation: true,
    },
  });
  popupWindow.center();
  // 加载弹窗页面
  popupWindow.loadFile(path.join(__dirname, `html/${fileName}`));
  popupWindow.webContents.once('did-finish-load', () => {
    if (fileData != null) {
      popupWindow.webContents.send('display-file', fileData);
    }
  });
  popupWindow.on('close', (event) => {
    popupWindow = null;
  });
}

///关闭弹窗
function closePopupWindow() {
  if (popupWindow) {
    popupWindow.close(); // 关闭弹窗
    popupWindow = null;
  }
}
///设置窗口大小
function setWindowSize(_, width, height) {
  if (popupWindow) {
    popupWindow.setBounds({ width, height });
  }
}

///获取可用串口列表
async function getSerialList() {
  try {
    const ports = await SerialPort.SerialPort.list();

    SerialPortStore.clear(); // 先清空旧数据
    ports.forEach(ob => {
      sendLog(`串口列表：{`);
      sendLog(`path:${ob.path}`);
      sendLog(`manufacturer:${ob.manufacturer}`);
      sendLog(`serialNumber:${ob.serialNumber}`);
      sendLog(`pnpId:${ob.pnpId}`);
      sendLog(`locationId:${ob.locationId}`);
      sendLog(`vendorId:${ob.vendorId}`);
      sendLog(`productId:${ob.productId}`);
      sendLog(`}`);
      SerialPortStore.addPort(ob);
    }); // 添加新数据

    return SerialPortStore.getAll();
  } catch (err) {
    console.error('Error listing serial ports:', err);
    return []; // 返回空数组表示没有可用串口
  }
}

///打开串口
async function openPort(event, portPath, portName, baudRate = 9600) {
  if (port) {
    if (port.path == portPath) {
      broadcastToAllWindows('listen-port', { isopen: true, msg: `端口${portName}已打开` });
      return;
    } else {
      port.close(); // 先关闭已有端口
      port = null;
    }
  }
  // 获取端口详细信息
  const ports = await SerialPort.SerialPort.list();
  const portInfo = ports.find(p => p.path === portPath);

  if (!portInfo) {
    broadcastToAllWindows('listen-port', { isopen: false, error: `未找到端口 ${portName} 的详细信息` });
    return;
  }

  // 创建 SerialPort 实例，并附加详细信息
  port = await new SerialPort.SerialPort({ path: portPath, baudRate });
  port.manufacturer = portInfo.manufacturer;
  port.serialNumber = portInfo.serialNumber;
  port.pnpId = portInfo.pnpId;
  port.locationId = portInfo.locationId;
  port.vendorId = portInfo.vendorId;
  port.productId = portInfo.productId;
  port.on('open', () => {
    broadcastToAllWindows('listen-port', { isopen: true, msg: `端口${portName}已打开` });
  });

  port.on('data', (buffer) => {
    broadcastToAllWindows('listen-port', { isopen: true, send: `${buffer.toHexString()}`, msg: `上位机收到端口'${portName}'上发的数据: ` });
  });

  port.on('close', () => {
    broadcastToAllWindows('listen-port', { isopen: false, msg: `端口关闭 :  ${portName}` });
  });

  port.on('error', (err) => {
    broadcastToAllWindows('listen-port', { isopen: false, error: `端口${portName}打开失败:${err.message}` });
  });

}

///关闭串口
function closePort() {
  if (port) {
    port.close();
    port = null;
  }
}

///发送数据
function sendData(event, message) {
  if (port && port.isOpen) {
    try {
      let dataToSend;
      if (message instanceof Uint8Array) {
        dataToSend = message;
      } else if (typeof message === "string" && message.isHexString()) {
        // 如果是十六进制字符串，转换成 Uint8Array
        dataToSend = message.hexStringToUint8Array();
      } else {
        broadcastToAllWindows('listen-port', { isopen: true, error: `数据格式错误: ${message}`, });
        return;
      }

      port.write(dataToSend, (err) => {
        if (err) {
          broadcastToAllWindows('listen-port', { isopen: true, error: err.message });
        } else {
          broadcastToAllWindows('listen-port', { isopen: true, received: `端口'${port.manufacturer}'收到上位机下发的数据: ${dataToSend.toHexString()}` });
        }
      });
    } catch (err) {
      broadcastToAllWindows('listen-port', { isopen: true, error: err.message });
    }
  } else {
    broadcastToAllWindows('listen-port', { isopen: false, error: `端口${port.manufacturer}没打开` });
  }
}

///用地址数组，采样率发送数据
async function sendDataWithList(event, head, cmd) {
  if (!Number.isInteger(head)) {
    broadcastToAllWindows('listen-port', { isopen: true, error: `数据格式错误：${head}不是整数类型` });
  } else if (!Number.isInteger(cmd)) {
    broadcastToAllWindows('listen-port', { isopen: true, error: `数据格式错误：${cmd}不是整数类型` });
  } else {


    ///1，先加入帧头，和命令
    let data = [head, cmd];
    ///2，获取地址模型数组中的地址
    // let temp1 = address_list.map(($0) => (cmd == 0x05 ? $0.changeValue : $0.address).hexStringToUint8Array()).flatMap(arr => [...arr]);
    const temp1 = address_list.map(($0) => {
      ///如果是修改值
      if (cmd == 0x05) {
        return ($0.signalType == '101' ? $0.changeValue.padEnd($0.changeValue.length + 6, '0') : $0.changeValue).hexStringToUint8Array();
      }
      return $0.address.hexStringToUint8Array();
    }).flatMap(arr => [...arr]);
    data.push(...temp1);

    ///3，拼接地址模型数组中的信号类型，flag信息
    let temp_type = address_list.map(($0) => $0.signalType).join('');
    const temp_flag = address_list.map(($0) => $0.flag).join('');
    temp_type = temp_type + temp_flag;
    temp_type = temp_type.padEnd(32, '0'); // 确保至少 4 个字节（32 位）

    ///4，判断拼接完成后，是否合规的二进制字符串
    if (!temp_type.isBinaryString()) {
      broadcastToAllWindows('listen-port', { isopen: true, error: `数据格式错误：${temp_type}不是正确的二进制字符串` });
    } else {
      ///5，二进制字符串转换成Uint8Array
      const temp2 = temp_type.binaryStringToUint8Array();
      data.push(...temp2);
      ///6，添加采样率
      const frency_str = await getStoreValue(null, 'my_frequency');
      const frency = parseInt(frency_str, 10);
      data.push(frency);
      ///7，添加校验值
      const crc = Uint8Array.from(data).crc();
      data.push(crc);
      ///发送数据
      sendData(event, Uint8Array.from(data));
    }
  }
}

///浏览本地文件
async function browseFiles() {
  const result = await dialog.showOpenDialog(mainWindow, {
    properties: ['openFile', 'multiSelections'], // 支持文件夹、文件和多选
    filters: [
      { name: 'Images', extensions: ['jpg', 'jpeg', 'png', 'gif', 'bmp', 'tiff', 'webp', 'JPG', 'JPEG', 'PNG', 'GIF', 'BMP', 'TIFF', 'WEBP'] }, // 图片文件扩展名
      { name: 'Videos', extensions: ['mp4', 'avi', 'mov', 'mkv', 'webm', 'flv', 'wmv'] }, // 视频文件扩展名
      { name: 'Text', extensions: ['txt', 'md', 'json', 'xml', 'csv'] }, // 文本文件扩展名
      { name: 'All Files', extensions: ['*'] }, // 所有文件
    ],
  });
  if (result.canceled || result.filePaths.length === 0) {
    return null; // 用户取消操作
  }

  let path = result.filePaths[0].toString();
  return path; // 返回选中的文件路径
}

///选择文件
async function chooseFile() {
  try {
    // 在 macOS 和 Windows 中，打开文件对话框并让用户选择一个文件（或颜色）
    const result = await dialog.showOpenDialog(mainWindow, {
      properties: ['openFile'], // 可以选择文件
      filters: [
        { name: 'Color', extensions: ['*'] } // 为了显示颜色文件类型，尽管它并不会直接触发颜色选择器
      ]
    });

    if (!result.canceled && result.filePaths.length > 0) {
      console.log('Selected file path or color file:', result.filePaths[0]);
      return result;
    } else {
      console.log('User canceled the color picker');
    }
  } catch (err) {
    console.error('Error in color picker dialog:', err);
  }
}

///阅读本地文件
async function readFiles(_, filePath) {
  try {
    const ext = path.extname(filePath).toLowerCase();
    if (['.txt', '.html', '.js', '.json', '.css', '.xml'].includes(ext)) {
      const content = await fs.readFileSync(filePath, 'utf-8'); // 文本文件
      return { type: 'text', content }
    } else if (['.jpg', '.png', '.gif'].includes(ext)) {
      // return await fs.readFileSync(filePath); // 二进制文件
      // shell.openPath(filePath);//直接拉打开窗口
      return { type: 'image', path: filePath };
    } else if (['.mp4', '.avi', '.mov'].includes(ext)) {
      // shell.openPath(filePath);
      return { type: 'video', path: filePath };
    } else {
      return { type: 'unknown', path: filePath };
    }
  } catch (err) {
    console.error('Error reading file:', err);
    return null;
  }
}

///弹出系统颜色选择器
async function showColorPicker(event, defaultColor = '#FF0000', id, index) {
  const platform = process.platform;
  let command;

  // 如果颜色选择器已经打开，先关闭它
  if (isColorPickerOpen && colorPickerProcess) {
    if (platform === 'win32') {
      // Windows: 终止进程
      exec(`taskkill /pid ${colorPickerProcess.pid} /f`);
    } else {
      // macOS 和 Linux: 终止进程
      colorPickerProcess.kill();
    }
    colorPickerProcess = null;
    isColorPickerOpen = false;
  }

  if (platform === 'win32') {
    // Windows: 使用 PowerShell 调用颜色选择器
    const r = parseInt(defaultColor.slice(1, 3), 16);
    const g = parseInt(defaultColor.slice(3, 5), 16);
    const b = parseInt(defaultColor.slice(5, 7), 16);

    // 构建 PowerShell 命令
    command = `powershell -Command "Add-Type -AssemblyName System.Windows.Forms; $colorDialog = New-Object System.Windows.Forms.ColorDialog; $colorDialog.Color = [System.Drawing.Color]::FromArgb(${r}, ${g}, ${b}); if ($colorDialog.ShowDialog() -eq 'OK') { $colorDialog.Color.ToArgb().ToString('X8') }"`;
  } else if (platform === 'darwin') {
    // macOS: 使用 AppleScript 调用颜色选择器
    const r = Math.round(parseInt(defaultColor.slice(1, 3), 16) / 255 * 65535);
    const g = Math.round(parseInt(defaultColor.slice(3, 5), 16) / 255 * 65535);
    const b = Math.round(parseInt(defaultColor.slice(5, 7), 16) / 255 * 65535);
    command = `osascript -e 'choose color default color {${r}, ${g}, ${b}}'`;
  } else if (platform === 'linux') {
    // Linux: 使用 zenity 调用颜色选择器
    command = `zenity --color-selection --color=${defaultColor}`;
  } else {
    event.reply('color-pick-error', 'Unsupported platform', id, index);
    return;
  }

  // 启动新的颜色选择器进程
  isColorPickerOpen = true; // 设置标志位为 true
  colorPickerProcess = spawn(command, { shell: true });

  let stdoutData = '';
  colorPickerProcess.stdout.on('data', (data) => {
    stdoutData += data.toString(); // 收集 stdout 数据
  });


  colorPickerProcess.on('close', (code) => {
    if (code === 0) {
      // 用户选择了颜色
      const color = parseColor(platform, stdoutData); // 使用收集的 stdout 数据
      event.reply('color-picked', color, id, index);
      console.log(`用户选择了颜色===》${color}`);
    } else {
      // 用户取消或出错
      // event.reply('color-pick-error', 'Color picker closed',id, index);
    }
  });

  colorPickerProcess.on('error', (err) => {
    isColorPickerOpen = false; // 重置标志位
    event.reply('color-pick-error', err.message, id, index);
    colorPickerProcess = null; // 重置进程
  });
}

///加载本地地址列表
async function loadAllAddress() {
  address_list = await AddressModel.getAll();
  return address_list;
}

///更行某个地址模型
async function updateAddress(event, model) {
  return await AddressModel.set(model);
}

///按ID寻找某个地址模型
async function findAddress(id) {
  return await AddressModel.get(id);
}

///加载本地通道列表 
async function loadAllChannel() {
  ch_list = await ChannelModel.getAll();
  return ch_list;
}

///更新某个通道
async function updateChannel(event, model) {
  broadcastToAllWindows('linsten-channel', {});
  return await ChannelModel.set(model);
}

///键值队获取值
async function getStoreValue(event, key, defaultValue) {
  return await config_store.get(key, defaultValue);
}
///键值队更新值
async function setStoreValue(event, key, value) {
  return await config_store.set(key, value);
}

///signal选择变化
function receiveSignSelect(_, model) {
  broadcastToAllWindows('listen-signal-select', model);
}

// 广播给所有渲染进程
function broadcastToAllWindows(channel, message) {
  if (message.error) {
    sendLog(`======== ${message.error}`);
  } else if (message.received) {
    sendLog(`======== ${message.received}`);
  } else if (message.send) {
    sendLog(`========${message.msg} ${message.send}`);
  } else if (message.msg) {
    sendLog(`======== ${message.msg}`);
  }
  BrowserWindow.getAllWindows().forEach(win => {
    win.webContents.send(channel, message);
  });
}

// 解析颜色值
function parseColor(platform, stdout) {
  if (platform === 'win32') {
    return parseWindowsColor(stdout);
  } else if (platform === 'darwin') {
    return parseMacColor(stdout);
  } else if (platform === 'linux') {
    return parseLinuxColor(stdout);
  }
  return '#000000'; // 默认返回黑色
}

// windows颜色转换成16进制字符串
function parseWindowsColor(stdout) {
  return `#${stdout.slice(2)}`;
}

//macos 颜色转换成16进制字符串
function parseMacColor(stdout) {
  const match = stdout.match(/\d+/g);
  if (!match) return null;
  const r = Math.round(parseInt(match[0], 10) / 65535 * 255);
  const g = Math.round(parseInt(match[1], 10) / 65535 * 255);
  const b = Math.round(parseInt(match[2], 10) / 65535 * 255);
  return rgbToHex(r, g, b);
}
// linux 颜色转换成16进制字符串
function parseLinuxColor(stdout) {
  const hex = stdout.trim().match(/#[0-9a-fA-F]{6}/)?.[0];
  return hex || '#000000';
}
// 10进制的rgb转换成16进制的rgb
function rgbToHex(r, g, b) {
  return `#${((1 << 24) + (r << 16) + (g << 8) + b).toString(16).slice(1)}`;
}

// 检查文件扩展名来判断文件类型
function isTextFile(filePath) {
  const ext = path.extname(filePath).toLowerCase();
  const textExtensions = ['.txt', '.html', '.js', '.json', '.css', '.xml']; // 常见文本文件扩展名
  return textExtensions.includes(ext);
}




///==============================================日志======================================================
let logWindow;
function hiddenLogWindow() {
  if (logWindow) {
    logWindow.hide();
  }
}
function createLogWindow() {
  if (logWindow) {
    console.log(`已经创建了窗口`);
    logWindow.setBounds({ x: 0, y: 0, width: 500, height: screenSize.height })
    logWindow.show();
    return; // 如果已经有窗口，就不再创建新的窗口
  }
  logWindow = new BrowserWindow({
    x: 0,
    y: 0,
    width: 500,
    height: screenSize.height,
    title: '日志窗口',
    autoHideMenuBar: true,
    webPreferences: {
      preload: path.join(__dirname, 'preload.js'),
      nodeIntegration: true,
      contextIsolation: true
    }
  });

  logWindow.loadFile(path.join(__dirname, 'html/logwindow.html'));
  logWindow.on('close', (event) => {
    event.preventDefault();
    logWindow.hide();
  });
}


// 监听主进程的日志消息，并转发给日志窗口
function sendLog(message) {
  broadcastToAllWindows('new-log', message);
}

// 监听渲染进程发来的日志消息
ipcMain.on('log-message', (_, message) => {
  sendLog(message);
});

module.exports = { sendLog };


///============================================================定义全局变量===================================================
const config_store = new StorageManager();
let address_list = null;
let ch_list = null;
///初始化数据 
async function initData() {
  ///先加载本地数据
  const frency_str = await getStoreValue(null, 'my_frequency');
  const baud_str = await getStoreValue(null, 'my_baud');
  await loadAllAddress();
  await loadAllChannel();

  if (!frency_str) {
    config_store.set('my_frequency', '100');
  }
  if (!baud_str) {
    config_store.set('my_baud', '115200');
  }
  if (!address_list || address_list.length < 1) {
    address_list = Array.from({ length: 6 }, (_, i) => new AddressModel(`${i + 1}`, `0000000${i + 1}`, '001', '1', '00000000'));
    AddressModel.set(address_list);
  }
  if (!ch_list || ch_list.length < 1) {
    const colorList = ['#fffd54', '#96cde8', '#f6c3cb', '#a6eb9a', '#0000ff', '#ff0000'];
    const signalSelect = Array(16).fill(0).join(',');
    ch_list = Array.from({ length: 6 }, (_, i) => {
      return new ChannelModel({
        id: `${i + 1}`,
        name: `通道${i + 1}`,
        color: colorList[i],
        weight: '1',
        minWeight: '0.5',
        maxWeight: '5',
        stepWeight: '0.1',
        show: true,
        options: '1',
        inputName: '100',
        signalSelect: signalSelect
      })
    });
    ChannelModel.set(ch_list);
  }
}

global.shareObject = {

}